home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Games Collection 1 / software vault.zip / software vault / CDR10 / MAPEDIT.ZIP / SAMPGAME / PCX.C < prev    next >
C/C++ Source or Header  |  1992-04-11  |  30KB  |  855 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <conio.h>
  5. #include <dos.h>
  6. #include <malloc.h>
  7. #include <graph.h>
  8.  
  9. #define FALSE           0
  10. #define TRUE            1
  11. #define PCX_HERC        0xff    /* Hercules 720 x 348 monochrome mode   */
  12. #define PCX_COMP_FLAG   0xc0    /* Compressed data flag mask            */
  13. #define PCX_COMP_MASK   0x3f    /* Data repeat count mask               */
  14. #define PCX_PAL_MASK    0x03    /* Palette interpretation mask          */
  15. #define PCX_EPAL_FLAG   0x0c    /* Extended palette flag                */
  16. #define PCX_PAL_SIZE    16      /* File header palette size             */
  17. #define PCX_EPAL_SIZE   256     /* Extended palette size                */
  18. #define PCX_CGA_BKGND(x)        (x[0].red >> 4)    /* Background color  */
  19. #define PCX_CGA_BURST(x)        (x[1].red & 0x80)  /* Color burst       */
  20. #define PCX_CGA_SELECT(x)       (x[1].red & 0x40)  /* Palette selector  */
  21. #define PCX_CGA_INTENSITY(x)    (x[1].red & 0x20)  /* Intensity         */
  22. #define PCX_MAXLINESZ   640     /* Maximum PCX line buffer size         */
  23.  
  24. typedef int BOOL;       /* Boolean flag                                 */
  25. typedef unsigned char BYTE;     /* 8-bit data type                      */
  26. typedef unsigned int WORD;      /* 16-bit data type                     */
  27.  
  28. typedef struct pcx_pal  /* PCX palette array element                    */
  29. {
  30.   BYTE red;             /* Red intensity                                */
  31.   BYTE green;           /* Green intensity                              */
  32.   BYTE blue;            /* Blue intensity                               */
  33. }PCX_PAL;
  34. struct mypal_struct{
  35.     int r;
  36.     int g;
  37.     int b;
  38. }mypal[256];
  39.  
  40. typedef struct pcx_hdr  /* PCX file header (Version 5)                  */
  41. {
  42.   BYTE pcx_id;          /* Always 0x0a for PCX files                    */
  43.   BYTE version;         /* Version number                               */
  44.   BYTE encoding;        /* 1 = PCX run length encoding                  */
  45.   BYTE bppixel;         /* Number of bits/pixel per color plane         */
  46.   WORD xul;             /* X-position of upper left corner              */
  47.   WORD yul;             /* Y-position of upper left corner              */
  48.   WORD xlr;             /* X-position of lower right corner             */
  49.   WORD ylr;             /* Y-position of lower right corner             */
  50.   WORD horz_res;        /* Horizontal resolution                        */
  51.   WORD vert_res;        /* Vertical resolution                          */
  52.   PCX_PAL palette[PCX_PAL_SIZE];        /* Hardware R-G-B palette       */
  53.   BYTE reserved;        /* Unused in Version 5                          */
  54.   BYTE nplanes;         /* Number of color planes                       */
  55.   WORD bppscan;         /* Number of bytes per plane scan line          */
  56.   WORD palette_type;    /* Palette interpretation                       */
  57.   WORD scrn_width;      /* Horizontal screen size in pixels             */
  58.   WORD scrn_height;     /* Vertical screen size in pixels               */
  59.   BYTE filler[54];      /* Padding to fill out 128-byte header          */
  60.  
  61. }PCX_HDR;
  62.  
  63. typedef struct pcx_workblk      /* PCX image file workblock             */
  64. {
  65.   /* File header                                                        */
  66.  
  67.   FILE *fp;                     /* PCX image file pointer               */
  68.   PCX_HDR header;               /* PCX image file header                */
  69.   PCX_PAL *palettep;            /* Color palette pointer                */
  70.   BOOL epal_flag;               /* Extended color palette flag          */
  71.  
  72.   /* Image manipulation variables                                       */
  73.  
  74.   int num_bytes;                /* Number of bytes to display           */
  75.   int mask;                     /* Unseen pixels mask                   */
  76.   unsigned long page_offset;    /* Display page address offset          */
  77.  
  78.   /* Image manipulation function pointer                                */
  79.  
  80.   void (*pcx_funcp)(struct pcx_workblk *, unsigned char _far *, int);
  81. } PCX_WORKBLK;
  82.  
  83. typedef struct pcx_vsb  /* BIOS video services data save buffer         */
  84. {
  85.   struct pcx_ppt                /* Primary Pointer Table                */
  86.   {
  87.     void _far *vptp;            /* Video Parameter Table pointer        */
  88.     unsigned char _far *dsap;   /* Dynamic Save Area pointer            */
  89.     void _far *tmacgp;          /* Text Mode Aux Char Generator pointer */
  90.     void _far *gmacgp;          /* Graphics Mode Aux Char Generator ptr */
  91.     void _far *sptp;            /* Secondary Pointer Table pointer      */
  92.     void _far *rsv_1;           /* Reserved                             */
  93.     void _far *rsv_2;           /* Reserved                             */
  94.   } pcx_ppt;
  95.   struct pcx_ppt _far *prev_pptp;
  96. }PCX_VSB;
  97.  
  98. static BOOL pcx_encode(int, int, FILE *);
  99. static BOOL pcx_init_palette(PCX_PAL *, int);
  100. static BOOL pcx_write_extpal(FILE *);
  101. static BOOL pcx_write_line(unsigned char *, int, FILE *);
  102. static BOOL pcx_write_init(PCX_WORKBLK *, int, int, int, int);
  103. static void pcx_get_cga(PCX_WORKBLK *, unsigned char _far *, int);
  104. static void pcx_get_ega(PCX_WORKBLK *, unsigned char _far *, int);
  105. static void pcx_get_herc(PCX_WORKBLK *, unsigned char _far *, int);
  106. static void pcx_get_vga(PCX_WORKBLK *, unsigned char _far *, int);
  107. static BOOL pcx_read_init(PCX_WORKBLK *, int, int);
  108. static BOOL pcx_read_extpal(PCX_WORKBLK *);
  109. static BOOL pcx_read_header(PCX_WORKBLK *);
  110. static BOOL pcx_read_line(PCX_WORKBLK *, unsigned char *, int);
  111. static BOOL pcx_set_palette(PCX_PAL *, int);
  112. static void pcx_put_vga(PCX_WORKBLK *, unsigned char _far *, int);
  113. BOOL pcx_close(PCX_WORKBLK *);
  114. BOOL load_pcx(char *, char far *);
  115. PCX_WORKBLK *pcx_open(char *, BOOL);
  116. BOOL pcx_init_dsa(PCX_VSB **);
  117. BOOL pcx_isvga(void);
  118. BOOL save_pcx(char *,char far *);
  119. void pcx_free_dsa(PCX_VSB *);
  120.  
  121.  
  122. char far *buf;
  123. char far *write_buf;
  124.  
  125.  
  126. static BYTE pcx_EGA_DefPal_1[16] =      /* Modes 0x0d and 0x0e          */
  127. {
  128.   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13,
  129.   0x14, 0x15, 0x16, 0x17
  130. };
  131.  
  132. static BYTE pcx_EGA_DefPal_2[16] =      /* Mode 0x0f                    */
  133. {
  134.   0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
  135.   0x00, 0x18, 0x00, 0x00
  136. };
  137.  
  138. static BYTE pcx_EGA_DefPal_3[16] =      /* Mode 0x10                    */
  139. {
  140.   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a, 0x3b, 
  141.   0x3c, 0x3d, 0x3e, 0x3f
  142. };
  143.  
  144.  
  145.  
  146. BOOL load_pcx(char *fname, char far *buffer)
  147. {
  148.     int bpline;                   /* Number of bytes per scan line        */
  149.     int line_num;                 /* Scan line number                     */
  150.     int max_lines;                /* Maximum number of scan lines         */
  151.     unsigned char *linep;         /* PCX scan line buffer pointer         */
  152.     BOOL status = TRUE;           /* Return status                        */
  153.     PCX_WORKBLK *wbp;             /* PCX image file workblock pointer     */
  154.     int vmode=0x13,page=0;
  155.  
  156.     buf=buffer;
  157.     /* Open a PCX image file workblock                                    */
  158.     if ((wbp = pcx_open(fname, FALSE)) == (PCX_WORKBLK *) NULL)
  159.         return (FALSE);
  160.     /* Initialize the workblock for reading                               */
  161.     if (pcx_read_init(wbp, vmode, page) == FALSE)
  162.     {
  163.         (void) pcx_close(wbp);      /* Close the PCX workblock              */
  164.         return (FALSE);
  165.     }
  166.     /* Calculate the image height                                         */
  167.     max_lines = wbp->header.yul + wbp->header.ylr + 1;
  168.     /* Calculate number of bytes per line (for all color planes)          */
  169.     bpline = wbp->header.bppscan * wbp->header.nplanes;
  170.     /* Allocate the PCX scan line buffer                                  */
  171.     if ((linep = (unsigned char *) malloc(bpline)) != (unsigned char *)NULL)
  172.     {
  173.         /* Set the file pointer to the beginning of the encoded image data  */
  174.  
  175.         if (fseek(wbp->fp, (long) (sizeof(PCX_HDR)), SEEK_SET) != 0)
  176.             status = FALSE;
  177.         if (pcx_set_palette(wbp->palettep, vmode) == FALSE)
  178.             status = FALSE;
  179.         /* Read the image line by line                                      */
  180.         for (line_num = 0; line_num < max_lines; line_num++)
  181.         {
  182.             /* Read the current scan line                                   */
  183.             if ((status = pcx_read_line(wbp, linep, bpline)) == FALSE)
  184.             {
  185.                 status = FALSE;
  186.                 break;
  187.             }
  188.             /* Display the current scan line                                */
  189.             wbp->pcx_funcp(wbp, (unsigned char _far *) linep, line_num);
  190.             free(linep);        /* Free the PCX scan line buffer         */
  191.         }
  192.     }
  193.     else
  194.         status = FALSE;
  195.     if (pcx_close(wbp) == FALSE)  /* Close the PCX workblock              */
  196.         status = FALSE;
  197.  
  198.     return (status);
  199. }
  200.  
  201.  
  202. static BOOL pcx_read_init(PCX_WORKBLK *wbp,int vmode,int page)
  203. {
  204.     int width;                    /* Display width                        */
  205.     int leftover;                 /* Number of unseen bits                */
  206.     BOOL status = TRUE;           /* Return status                        */
  207.  
  208.     /* Read the file header                                               */
  209.  
  210.     if ((pcx_read_header(wbp)) == FALSE)
  211.         return (FALSE);
  212.  
  213.     /* Initialize the workblock color palette pointer                     */
  214.  
  215.     wbp->palettep = wbp->header.palette;
  216.     wbp->epal_flag = FALSE;
  217.  
  218.     /* Read the extended palette (if any)                                 */
  219.  
  220.         if (pcx_read_extpal(wbp) == FALSE)
  221.             return (FALSE);
  222.  
  223.     /* Initialize the display page address offset                         */
  224.  
  225.     wbp->page_offset = (unsigned long) 0L;
  226.     /* Calculate number of bytes to display                           */
  227.     wbp->num_bytes = min((wbp->header.xlr - wbp->header.xul + 1), 320);
  228.     wbp->mask = 0;  /* Dummy parameter                                */
  229.     wbp->pcx_funcp = pcx_put_vga;     /* Set the display function ptr */
  230.  
  231.  
  232.     return (status);
  233. }
  234.  
  235.  
  236. static BOOL pcx_read_header(PCX_WORKBLK *wbp)
  237. {
  238.     BOOL status = TRUE;   /* Status flag                                  */
  239.     PCX_HDR *hdrp;        /* PCX file header buffer pointer               */
  240.  
  241.     hdrp = &(wbp->header);        /* Initialize the file header pointer   */
  242.  
  243.     /* Read the file header                                               */
  244.  
  245.     if (fseek(wbp->fp, 0L, SEEK_SET) != 0)
  246.         status = FALSE;
  247.     if (fread(hdrp, sizeof(PCX_HDR), 1, wbp->fp) != 1)
  248.         status = FALSE;
  249.     /* Validate the PCX file format                                       */
  250.     if ((hdrp->pcx_id != 0x0a) || (hdrp->encoding != 1))
  251.         status = FALSE;
  252.     return (status);
  253. }
  254.  
  255.  
  256. static BOOL pcx_read_extpal( PCX_WORKBLK *wbp )
  257. {
  258.     int indicator;        /* PCX extended palette indicator               */
  259.  
  260.     /* Position the file pointer to the extended palette indicator byte   */
  261.  
  262.     if (fseek(wbp->fp, -769L, SEEK_END) != 0)
  263.         return (FALSE);
  264.  
  265.     /* Read the (assumed) extended palette indicator byte                 */
  266.  
  267.     if ((indicator = getc(wbp->fp)) == EOF)
  268.         return (FALSE);
  269.  
  270.     if (indicator == PCX_EPAL_FLAG)       /* Check for indicator byte     */
  271.     {
  272.         /* Allocate an extended palette buffer                              */
  273.  
  274.         if ((wbp->palettep = (PCX_PAL *) calloc(sizeof(PCX_PAL),
  275.         PCX_EPAL_SIZE)) == (PCX_PAL *) NULL)
  276.             return (FALSE);
  277.  
  278.         /* Read the extended palette                                        */
  279.  
  280.         if (fread(wbp->palettep, sizeof(PCX_PAL), PCX_EPAL_SIZE, wbp->fp) !=
  281.             PCX_EPAL_SIZE)
  282.         {
  283.             free(wbp->palettep);      /* Free the extended palette buffer     */
  284.             return (FALSE);
  285.         }
  286.  
  287.         wbp->epal_flag = TRUE;      /* Indicate extended palette present    */
  288.     }
  289.  
  290.     return (TRUE);
  291. }
  292.  
  293.  
  294. static BOOL pcx_read_line(PCX_WORKBLK *wbp,unsigned char *linep,int bpline)
  295. {
  296.     int data;             /* Image data byte                              */
  297.     int count;            /* Image data byte repeat count                 */
  298.     int offset = 0;       /* Scan line buffer offset                      */
  299.  
  300.     while (offset < bpline)       /* Decode current scan line             */
  301.     {
  302.         if ((data = getc(wbp->fp)) == EOF)  /* Get next byte                */
  303.             return (FALSE);
  304.  
  305.         /* If top two bits of byte are set, lower six bits show how         */
  306.         /* many times to duplicate next byte                                */
  307.  
  308.         if ((data & PCX_COMP_FLAG) == PCX_COMP_FLAG)
  309.         {
  310.             count = data & PCX_COMP_MASK;     /* Mask off repeat count        */
  311.  
  312.             if ((data = getc(wbp->fp)) == EOF)        /* Get next byte        */
  313.                 return (FALSE);
  314.  
  315.             memset(linep, data, count);       /* Duplicate byte               */
  316.             linep += count;
  317.             offset += count;
  318.         }
  319.         else
  320.         {
  321.             *linep++ = (unsigned char) data;  /* Copy byte                    */
  322.             offset++;
  323.         }
  324.     }
  325.  
  326.     return (TRUE);
  327. }
  328.  
  329. static BOOL pcx_set_palette(PCX_PAL *palettep,int vmode)
  330. {
  331.     int i;                        /* Scratch counter                      */
  332.  
  333.     for (i = 0; i < PCX_EPAL_SIZE; i++)
  334.         pcx_setDAC(i,palettep[i].red >> 2,palettep[i].green>>2,palettep[i].blue>>2);
  335.     return (TRUE);
  336. }
  337.  
  338. pcx_setDAC(int n,int r,int g,int b)
  339. {
  340.     outp(0x3c8,n);
  341.     outp(0x3c9,r);
  342.     outp(0x3c9,g);
  343.     outp(0x3c9,b);
  344.     mypal[n].r=r;
  345.     mypal[n].g=g;
  346.     mypal[n].b=b;
  347. }
  348.  
  349.  
  350. static void pcx_put_vga(PCX_WORKBLK *wbp,unsigned char _far *linep,int line_num)
  351. {
  352.     unsigned char _far *displayp;         /* Display buffer pointer       */
  353.  
  354.     /* Calculate buffer pointer                                           */
  355.  
  356.     displayp = (unsigned char _far *)buf + line_num * 320;
  357.  
  358.     /* Copy data from the scan line buffer to the VGA display buffer      */
  359.  
  360.     (void) _fmemcpy(displayp, linep, wbp->num_bytes);
  361. }
  362.  
  363. PCX_WORKBLK *pcx_open
  364. (
  365.   char *fname,
  366.   BOOL wrt_flag
  367. )
  368. {
  369.   PCX_WORKBLK *wbp;     /* PCX image file workblock pointer             */
  370.  
  371.   /* Allocate a workblock                                               */
  372.  
  373.   if ((wbp = (PCX_WORKBLK *) malloc(sizeof(PCX_WORKBLK))) == NULL)
  374.     return (NULL);
  375.  
  376.   /* Open the PCX image file in binary mode                             */
  377.  
  378.   if (wrt_flag == FALSE)
  379.     wbp->fp = fopen(fname, "rb");       /* Open for reading             */
  380.   else
  381.     wbp->fp = fopen(fname, "wb");       /* Open for writing             */
  382.  
  383.   if (wbp->fp == NULL)  /* Check for successful file opening            */
  384.   {
  385.     free(wbp);          /* Free the workblock memory                    */
  386.     return (NULL);
  387.   }
  388.  
  389.   return (wbp);         /* Return the workblock pointer                 */
  390. }
  391.  
  392.  
  393. BOOL pcx_close
  394. (
  395.   PCX_WORKBLK *wbp
  396. )
  397. {
  398.   free(wbp->palettep);  /* Free the extended palette (if it exists)     */
  399.  
  400.   free(wbp);            /* Free the PCX image file workblock            */
  401.  
  402.   if (fclose(wbp->fp) == EOF)   /* Close the PCX image file             */
  403.     return (FALSE);
  404.  
  405.   return (TRUE);
  406. }
  407.  
  408.  
  409. BOOL pcx_isvga(void)
  410. {
  411.   unsigned char *vinfop;        /* VGA information buffer pointer       */
  412.   union REGS regs;              /* 80x86 register values                */
  413.   struct SREGS sregs;           /* 80x86 segment register values        */
  414.  
  415.   /* Allocate a VGA functionality/state information buffer              */
  416.  
  417.   if ((vinfop = (unsigned char *) malloc(sizeof(unsigned char) * 64)) ==
  418.       NULL)
  419.     return (FALSE);
  420.  
  421.   /* Attempt to read the VGA information                                */
  422.  
  423.   regs.h.ah = 0x1b;     /* Select "Return VGA Info" BIOS routine        */
  424.   regs.x.bx = 0;        /* Implementation type                          */
  425.  
  426.   /* Get the VGA information buffer offset value                        */
  427.  
  428.   regs.x.di = (unsigned int) vinfop;
  429.  
  430.   segread(&sregs);      /* Get the current DS segment register value    */
  431.  
  432.   sregs.es = sregs.ds;
  433.  
  434.   int86x(0x10, ®s, ®s, &sregs);   /* Call BIOS video service      */
  435.  
  436.   free(vinfop);         /* Free the VGA information buffer              */
  437.  
  438.   /* The value 0x1b is returned in register AL only if a VGA display    */
  439.   /* adapter is present                                                 */
  440.  
  441.   if (regs.h.al == 0x1b)
  442.     return (TRUE);
  443.   else
  444.     return (FALSE);
  445. }
  446.  
  447.  
  448. BOOL save_pcx
  449. (
  450.   char *fname,
  451.   char far * buffer,
  452. )
  453. {
  454.   int bpline;                   /* Number of bytes per scan line        */
  455.   int line_num;                 /* Scan line number                     */
  456.   unsigned char *linep;         /* Image scan line buffer pointer       */
  457.   BOOL status = TRUE;           /* Return status                        */
  458.   PCX_WORKBLK *wbp;             /* PCX image file workblock pointer     */
  459.   int width=320;
  460.   int height=200;
  461.   int vmode=0x13;
  462.   int page=0;
  463.  
  464.     write_buf=buffer;
  465.  
  466.   /* Open a PCX image file workblock                                    */
  467.  
  468.   if ((wbp = pcx_open(fname, TRUE)) == (PCX_WORKBLK *) NULL)
  469.     return (FALSE);
  470.  
  471.   /* Initialize the workblock for writing                               */
  472.  
  473.   if (pcx_write_init(wbp, vmode, page, width, height) == FALSE)
  474.     status = FALSE;
  475.  
  476.   /* Calculate number of bytes per line (for all color planes)          */
  477.  
  478.   bpline = wbp->header.bppscan * wbp->header.nplanes;
  479.  
  480.   /* Allocate a scan line buffer                                        */
  481.  
  482.   if (status == TRUE)
  483.     if ((linep = (unsigned char *) malloc(bpline)) == (unsigned char *)
  484.         NULL)
  485.       status = FALSE;
  486.  
  487.   /* Write the file header to the file                                  */
  488.  
  489.   if (status == TRUE)
  490.     if (fwrite(&(wbp->header), sizeof(PCX_HDR), 1, wbp->fp) != 1)
  491.       status = FALSE;
  492.  
  493.   /* Write the encoded image data to the file                           */
  494.  
  495.   if (status == TRUE)
  496.   {
  497.     for (line_num = 0; line_num <= (int) wbp->header.ylr; line_num++)
  498.     {
  499.       /* Get the current video buffer scan line                         */
  500.  
  501.       wbp->pcx_funcp(wbp, (unsigned char _far *) linep, line_num);
  502.  
  503.       /* Encode the scan line and write it to the file                  */
  504.  
  505.       if (pcx_write_line(linep, bpline, wbp->fp) == FALSE)
  506.       {
  507.         status = FALSE;
  508.         break;
  509.       }
  510.     }
  511.   }
  512.     if (status == TRUE)
  513.       if (pcx_write_extpal(wbp->fp) == FALSE)
  514.         status = FALSE;
  515.   if (pcx_close(wbp) == FALSE)  /* Close the PCX workblock              */
  516.     status = FALSE;
  517.  
  518.   free(linep);          /* Free the scan line buffer                    */
  519.  
  520.   /* Remove the PCX image file if an error occurred                     */
  521.  
  522.   if (status == FALSE)
  523.     (void) remove(fname);
  524.  
  525.   return (status);
  526. }
  527.  
  528.  
  529. BOOL pcx_init_dsa
  530. (
  531.   PCX_VSB **vsbpp
  532. )
  533. {
  534.   unsigned char _far *dsap;     /* Dynamic Save Area pointer            */
  535.   PCX_VSB *vsbp;                /* Video services data save buffer ptr  */
  536.  
  537.   *vsbpp = (PCX_VSB *) NULL;    /* Initialize returned pointer          */
  538.  
  539.   /* Allocate a Dynamic Save Area buffer                                */
  540.  
  541.   if ((dsap = (unsigned char _far *) _fmalloc(sizeof(unsigned char) *
  542.       256)) == (unsigned char _far *) NULL)
  543.     return (FALSE);
  544.  
  545.   /* Allocate a BIOS video services data save buffer                    */
  546.  
  547.   if ((vsbp = (PCX_VSB *) malloc(sizeof(PCX_VSB))) == (PCX_VSB *) NULL)
  548.   {
  549.     _ffree(dsap);       /* Free the Dynamic Save Area buffer            */
  550.     return (FALSE);
  551.   }
  552.  
  553.   /* Save the existing Primary Pointer Table pointer                    */
  554.  
  555.   vsbp->prev_pptp = *((struct pcx_ppt _far * _far *) 0x004000a8L);
  556.  
  557.   /* Copy the existing Primary Pointer Table into the buffer            */
  558.  
  559.   (void) _fmemcpy((struct pcx_ppt _far *) &(vsbp->pcx_ppt),
  560.       vsbp->prev_pptp, sizeof(struct pcx_ppt));
  561.  
  562.   vsbp->pcx_ppt.dsap = dsap;    /* Update the Dynamic Save Area ptr     */
  563.  
  564.   /* Update the Primary Pointer Table pointer in the Video Save Table   */
  565.  
  566.   *((struct pcx_ppt _far * _far *) 0x004000a8L) = &(vsbp->pcx_ppt);
  567.  
  568.   *vsbpp = vsbp;        /* Return Video Services data save buffer ptr   */
  569.  
  570.   return (TRUE);
  571. }
  572.  
  573.  
  574. void pcx_free_dsa
  575. (
  576.   PCX_VSB *vsbp
  577. )
  578. {
  579.   /* Restore the previous primary pointer table pointer                 */
  580.  
  581.   *((struct pcx_ppt _far * _far *) 0x004000a8L) = vsbp->prev_pptp;
  582.  
  583.   _ffree(vsbp->pcx_ppt.dsap);   /* Free the Dynamic Save Area           */
  584.  
  585.   free(vsbp);   /* Free the Video Services data save buffer             */
  586. }
  587.  
  588.  
  589. static BOOL pcx_write_init
  590. (
  591.   PCX_WORKBLK *wbp,
  592.   int vmode,
  593.   int page,
  594.   int width,
  595.   int height
  596. )
  597. {
  598.   int max_width;        /* Maximum image width                          */
  599.   int max_height;       /* Maximum image height                         */
  600.   int shift;            /* Mask shift value                             */
  601.   BOOL status = TRUE;   /* Return status                                */
  602.   PCX_HDR *hdrp;        /* File header buffer pointer                   */
  603.  
  604.   /* Initialize the display page address offset                         */
  605.  
  606.   wbp->page_offset = (unsigned long) 0L;
  607.  
  608.   hdrp = &(wbp->header);        /* Initialize the file header pointer   */
  609.  
  610.   /* Initialize the header constants                                    */
  611.  
  612.   hdrp->pcx_id = 0x0a;          /* PCX format identifier                */
  613.   hdrp->version = 5;            /* Version number                       */
  614.   hdrp->encoding = 1;           /* Encoding format (run-length)         */
  615.   hdrp->xul = 0;                /* Upper left x-position                */
  616.   hdrp->yul = 0;                /* Upper left y-position                */
  617.   hdrp->reserved = 0;           /* (Used to be video mode)              */
  618.   hdrp->palette_type = 1;       /* Color or b&w palette type            */
  619.  
  620.   memset(hdrp->filler, 0, sizeof(hdrp->filler));        /* Padding      */
  621.  
  622.   /* Initialize the video mode-dependent parameters                     */
  623.  
  624.  
  625.       max_width = min(width, 320);      /* Maximum image width          */
  626.       max_height = min(height, 200);    /* Maximum image height         */
  627.  
  628.       hdrp->bppixel = 8;                /* Bits per pixel               */
  629.       hdrp->horz_res = 320;             /* Horizontal resolution        */
  630.       hdrp->vert_res = 200;             /* Vertical resolution          */
  631.       hdrp->nplanes = 1;                /* Number of color planes       */
  632.  
  633.       /* Calculate number of bytes to copy                              */
  634.  
  635.       wbp->num_bytes = max_width;
  636.  
  637.       shift = 0;        /* Dummy parameter                              */
  638.  
  639.       wbp->pcx_funcp = pcx_get_vga;     /* Set display capture fcn ptr  */
  640.  
  641.  
  642.   /* Initialize common video mode-dependent parameters                  */
  643.  
  644.   hdrp->xlr = max_width - 1;            /* Lower right x-position       */
  645.   hdrp->ylr = max_height - 1;           /* Lower right y-position       */
  646.   hdrp->scrn_width = hdrp->horz_res;    /* Screen width                 */
  647.   hdrp->scrn_height = hdrp->vert_res;   /* Screen height                */
  648.  
  649.   /* Calculate mask for "white" data                                    */
  650.  
  651.   if (shift != 0)
  652.     wbp->mask = 0xff >> shift;
  653.   else
  654.     wbp->mask = 0x00;
  655.  
  656.   /* Initialize the file header palette                                 */
  657.  
  658.   status = pcx_init_palette(hdrp->palette, vmode);
  659.  
  660.   /* Calculate number of bytes per color plane scan line (must be an    */
  661.   /* even number of bytes)                                              */
  662.  
  663.   hdrp->bppscan = 2 * (((((hdrp->xlr * hdrp->bppixel) + 7) / 8) + 1) / 2);
  664.  
  665.   return (status);
  666. }
  667.  
  668.  
  669. static BOOL pcx_init_palette
  670. (
  671.   PCX_PAL *palettep,
  672.   int vmode
  673. )
  674. {
  675.   int i;                        /* Scratch counter                      */
  676.   int val;                      /* Current palette register value       */
  677.   int red;                      /* Temporary value                      */
  678.   int green;                    /* Temporary value                      */
  679.   int blue;                     /* Temporary value                      */
  680.   unsigned char *ega_palp;      /* EGA/VGA palette buffer pointer       */
  681.   unsigned char _far *dsap;     /* Dynamic Save Area pointer            */
  682.   union REGS regs;              /* 80x86 register values                */
  683.   struct SREGS sregs;           /* 80x86 segment register values        */
  684.  
  685.  
  686.     memset(palettep, 0, sizeof(PCX_PAL) * PCX_PAL_SIZE);
  687.  
  688.   return (TRUE);
  689. }
  690.  
  691. static BOOL pcx_write_line
  692. (
  693.   unsigned char *linep,
  694.   int buflen,
  695.   FILE *fp
  696. )
  697. {
  698.   int curr_data;        /* Current data byte                            */
  699.   int prev_data;        /* Previous data byte                           */
  700.   int data_count;       /* Data repeat count                            */
  701.   int line_count;       /* Scan line byte count                         */
  702.  
  703.   prev_data = *linep++;         /* Initialize the previous data byte    */
  704.   data_count = 1;
  705.   line_count = 1;
  706.  
  707.   while (line_count < buflen)   /* Encode scan line                     */
  708.   {
  709.     curr_data = *linep++;       /* Get the current data byte            */
  710.     line_count++;               /* Increment the scan line counter      */
  711.  
  712.     if (curr_data == prev_data)         /* Repeating data bytes ?       */
  713.     {
  714.       data_count++;     /* Increment the data repeat count              */
  715.  
  716.       /* Check for maximum allowable repeat count                       */
  717.  
  718.       if (data_count == PCX_COMP_MASK)
  719.       {
  720.         /* Encode the data                                              */
  721.  
  722.         if (pcx_encode(prev_data, data_count, fp) == FALSE)
  723.           return (FALSE);
  724.  
  725.         data_count = 0;         /* Reset the data repeat count          */
  726.       }
  727.     }
  728.     else    /* End of repeating data bytes                              */
  729.     {
  730.       if (data_count > 0)
  731.       {
  732.         /* Encode the data                                              */
  733.  
  734.         if (pcx_encode(prev_data, data_count, fp) == FALSE)
  735.           return (FALSE);
  736.       }
  737.  
  738.       prev_data = curr_data;    /* Current data byte now previous       */
  739.       data_count = 1;
  740.     }
  741.   }
  742.  
  743.   if (data_count > 0)   /* Any remaining data ?                         */
  744.   {
  745.     /* Encode the data                                                  */
  746.  
  747.     if (pcx_encode(prev_data, data_count, fp) == FALSE)
  748.       return (FALSE);
  749.   }
  750.  
  751.   return (TRUE);
  752. }
  753.  
  754. static BOOL pcx_encode
  755. (
  756.   int data,
  757.   int count,
  758.   FILE *fp
  759. )
  760. {
  761.   if (((data & PCX_COMP_FLAG) == PCX_COMP_FLAG) || count > 1)
  762.   {
  763.     /* Write the count byte                                             */
  764.  
  765.     if (putc(PCX_COMP_FLAG | count, fp) == EOF)
  766.       return (FALSE);
  767.   }
  768.  
  769.   /* Write the data byte                                                */
  770.  
  771.   if (putc(data, fp) == EOF)
  772.     return (FALSE);
  773.  
  774.   return (TRUE);
  775. }
  776.  
  777.  
  778. static BOOL pcx_write_extpal
  779. (
  780.   FILE *fp
  781. )
  782. {
  783.   int i;                        /* Scratch counter                      */
  784.   BOOL status = TRUE;           /* Return status                        */
  785.   PCX_PAL *palettep;            /* Extended PCX palette buffer pointer  */
  786.   unsigned char *vga_palp;      /* 256-color VGA palette buffer pointer */
  787.   union REGS regs;              /* 80x86 register values                */
  788.   struct SREGS sregs;           /* 80x86 segment register values        */
  789.  
  790.   /* Allocate an extended PCX palette buffer                            */
  791.  
  792.   if ((palettep = (PCX_PAL *) calloc(sizeof(PCX_PAL), PCX_EPAL_SIZE)) ==
  793.       (PCX_PAL *) NULL)
  794.     return (FALSE);
  795.  
  796.   /* Allocate a 256-color VGA palette buffer                            */
  797.  
  798.   if ((vga_palp = (unsigned char *) calloc(sizeof(unsigned char), 768))
  799.       == (unsigned char *) NULL)
  800.   {
  801.     free(palettep);     /* Free the extended PCX palette buffer         */
  802.     return (FALSE);
  803.   }
  804.  
  805.   for (i = 0; i < PCX_EPAL_SIZE; i++)
  806.   {
  807.     palettep[i].red = mypal[i].r<<2;
  808.     palettep[i].green = mypal[i].g<<2;
  809.     palettep[i].blue = mypal[i].b<<2;
  810.   }
  811.  
  812.   /* Write the extended PCX palette indicator byte to the file          */
  813.  
  814.   if (status == TRUE)
  815.     if (fputc(PCX_EPAL_FLAG, fp) == EOF)
  816.       status = FALSE;
  817.  
  818.   /* Write the extended PCX palette to the file                         */
  819.  
  820.   if (status == TRUE)
  821.     if (fwrite(palettep, sizeof(PCX_PAL), PCX_EPAL_SIZE, fp) !=
  822.         PCX_EPAL_SIZE)
  823.       status = FALSE;
  824.  
  825.   free(palettep);       /* Free the extended PCX palette buffer         */
  826.  
  827.   free(vga_palp);       /* Free the VGA palette buffer                  */
  828.  
  829.   return (status);
  830. }
  831.  
  832. static void pcx_get_vga
  833. (
  834.   PCX_WORKBLK *wbp,
  835.   unsigned char _far *linep,
  836.   int line_num
  837. )
  838. {
  839.   unsigned char _far *displayp;         /* Display buffer pointer       */
  840.  
  841.   /* Calculate buffer pointer                                           */
  842.  
  843.   displayp = (unsigned char _far *) write_buf + line_num * 320;
  844.  
  845.   /* Copy data from the VGA display buffer to the scan line buffer      */
  846.  
  847.   (void) _fmemcpy(linep, displayp, wbp->num_bytes);
  848.  
  849.   /* Pad scan line with "white" data byte (if necessary)                */
  850.  
  851.   if (wbp->num_bytes & 1)
  852.     linep[wbp->num_bytes] = 0xff;
  853. }
  854.  
  855.